/*
 * Copyright (c) 2024 Yunshan Networks
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef TRACE_UTILS_H
#define TRACE_UTILS_H

/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */

#include <stdint.h>
#include "consts.h"

#define LUA_RUNTIME_DETECT_METHOD_LEN 256

#define LUA_RUNTIME_PATH_LEN 1024

#define LUA_RUNTIME_VERSION_LEN 32

#define UNWIND_ENTRIES_PER_SHARD 65535

#define UNWIND_SHARDS_PER_PROCESS 256

enum CfaType {
    CFA_TYPE_RBP_OFFSET,
    CFA_TYPE_RSP_OFFSET,
    CFA_TYPE_EXPRESSION,
    CFA_TYPE_UNSUPPORTED,
    CFA_TYPE_NO_ENTRY,
};
typedef uint8_t CfaType;

enum RegType {
    REG_TYPE_UNDEFINED,
    REG_TYPE_SAME_VALUE,
    REG_TYPE_OFFSET,
    REG_TYPE_UNSUPPORTED,
};
typedef uint8_t RegType;

typedef struct lua_unwind_table_t lua_unwind_table_t;

typedef struct python_unwind_table_t python_unwind_table_t;

typedef struct unwind_table_t unwind_table_t;

typedef struct {
    uint32_t kind;
    uint8_t version[LUA_RUNTIME_VERSION_LEN];
    uint8_t detection_method[LUA_RUNTIME_DETECT_METHOD_LEN];
    uint8_t path[LUA_RUNTIME_PATH_LEN];
} lua_runtime_info_t;

typedef struct {
    uint32_t id;
    uint16_t entry_start;
    uint16_t entry_end;
    uint64_t offset;
    uint64_t pc_min;
    uint64_t pc_max;
} shard_info_t;

typedef struct {
    uint8_t len;
    shard_info_t entries[UNWIND_SHARDS_PER_PROCESS];
} process_shard_list_t;

typedef struct {
    uint64_t pc;
    CfaType cfa_type;
    RegType rbp_type;
    int16_t cfa_offset;
    int16_t rbp_offset;
} unwind_entry_t;

typedef struct {
    uint32_t id;
    uint32_t len;
    unwind_entry_t entries[UNWIND_ENTRIES_PER_SHARD];
} unwind_entry_shard_t;

typedef struct {
    uint64_t thread_state_address;
    uint8_t offsets_id;
} python_unwind_info_t;

typedef struct {
    int64_t current_frame;
} py_cframe_t;

typedef struct {
    int64_t co_filename;
    int64_t co_firstlineno;
    int64_t co_name;
    int64_t co_varnames;
} py_code_object_t;

typedef struct {
    int64_t f_back;
    int64_t f_code;
    int64_t f_lineno;
    int64_t f_localsplus;
} py_frame_object_t;

typedef struct {
    int64_t owner;
} py_interpreter_frame_t;

typedef struct {
    int64_t tstate_head;
} py_interpreter_state_t;

typedef struct {
    int64_t ob_type;
} py_object_t;

typedef struct {
    int64_t interp_main;
} py_runtime_state_t;

typedef struct {
    int64_t data;
    int64_t size;
} py_string_t;

typedef struct {
    int64_t cframe;
    int64_t frame;
    int64_t interp;
    int64_t native_thread_id;
    int64_t next;
    int64_t thread_id;
} py_thread_state_t;

typedef struct {
    int64_t ob_item;
} py_tuple_object_t;

typedef struct {
    int64_t tp_name;
} py_type_object_t;

typedef struct {
    py_cframe_t cframe;
    py_code_object_t code_object;
    py_frame_object_t frame_object;
    py_interpreter_frame_t interpreter_frame;
    py_interpreter_state_t interpreter_state;
    py_object_t object;
    py_runtime_state_t runtime_state;
    py_string_t string;
    py_thread_state_t thread_state;
    py_tuple_object_t tuple_object;
    py_type_object_t type_object;
} python_offsets_t;

typedef struct {
    uint8_t offsets_id;
    uint8_t reserved[7];
    uint64_t state_address;
} lua_unwind_info_t;

typedef struct {
    uint32_t features;
    uint32_t off_l_ci;
    uint32_t off_l_base_ci;
    uint32_t off_l_end_ci;
    uint32_t off_ci_func;
    uint32_t off_ci_top;
    uint32_t off_ci_savedpc;
    uint32_t off_ci_prev;
    uint32_t off_tvalue_tt;
    uint32_t off_tvalue_val;
    uint32_t off_closure_isc;
    uint32_t off_lclosure_p;
    uint32_t off_cclosure_f;
    uint32_t off_proto_source;
    uint32_t off_proto_linedefined;
    uint32_t off_proto_code;
    uint32_t off_proto_sizecode;
    uint32_t off_proto_lineinfo;
    uint32_t off_proto_abslineinfo;
    uint32_t off_tstring_len;
    uint32_t sizeof_tstring;
    uint32_t sizeof_callinfo;
    uint32_t sizeof_tvalue;
} lua_ofs;

typedef struct {
    uint8_t fr2;
    uint8_t gc64;
    uint16_t pad;
    uint32_t tv_sz;
    uint32_t off_l_base;
    uint32_t off_l_stack;
    uint32_t off_gcproto_firstline;
    uint32_t off_gcproto_chunkname;
    uint32_t off_gcstr_data;
    uint32_t off_gcfunc_cfunc;
    uint32_t off_gcfunc_ffid;
    uint32_t off_gcfunc_pc;
    uint32_t off_gcproto_bc;
    uint32_t off_gcstr_len;
    uint32_t off_l_glref;
    uint32_t off_global_state_dispatchmode;
} lj_ofs;

bool frame_pointer_heuristic_check(uint32_t pid);

int32_t is_lua_process(uint32_t pid);

bool is_python_process(uint32_t pid);

int32_t lua_detect(uint32_t pid, lua_runtime_info_t *out);

char *lua_format_folded_stack_trace(void *tracer,
                                    uint32_t pid,
                                    const uint64_t *frames,
                                    uint32_t frame_count,
                                    bool new_cache,
                                    void *info_p,
                                    const char *err_tag);

void lua_set_map_fds(int32_t lang_flags_fd,
                     int32_t unwind_info_fd,
                     int32_t lua_offsets_fd,
                     int32_t luajit_offsets_fd);

lua_unwind_table_t *lua_unwind_table_create(int32_t lang_flags_fd,
                                            int32_t unwind_info_fd,
                                            int32_t lua_offsets_fd,
                                            int32_t luajit_offsets_fd);

void lua_unwind_table_destroy(lua_unwind_table_t *table);

void lua_unwind_table_load(lua_unwind_table_t *table, uint32_t pid);

void lua_unwind_table_unload(lua_unwind_table_t *table, uint32_t pid);

size_t merge_lua_stacks(void *trace_str, size_t len, const void *u_trace, const void *i_trace);

size_t merge_python_stacks(void *trace_str, size_t len, const void *i_trace, const void *u_trace);

int32_t protect_cpu_affinity_c(void);

python_unwind_table_t *python_unwind_table_create(int32_t unwind_info_map_fd,
                                                  int32_t offsets_map_fd);

void python_unwind_table_destroy(python_unwind_table_t *table);

void python_unwind_table_load(python_unwind_table_t *table, uint32_t pid);

void python_unwind_table_unload(python_unwind_table_t *table, uint32_t pid);

int32_t read_offset_of_stack_in_task_struct(void);

int rustc_demangle(const char *mangled, char *out, size_t out_size);

unwind_table_t *unwind_table_create(int32_t process_shard_list_map_fd,
                                    int32_t unwind_entry_shard_map_fd);

void unwind_table_destroy(unwind_table_t *table);

void unwind_table_load(unwind_table_t *table, uint32_t pid);

void unwind_table_unload(unwind_table_t *table, uint32_t pid);

void unwind_table_unload_all(unwind_table_t *table);

#endif  /* TRACE_UTILS_H */
